﻿#include "LuaState.h"
#include "LuaObjectImpl.h"
#include "LuaTable.h"
#include "LuaFunction.h"
#include "LuaUtf.h"
#include <string>
#include <sstream>

#define MIN_STACK_SIZE 64

LuaMalloc::LuaMalloc(lua_State* L)
{
	m_alloc=lua_getallocf(L,(void**)&m_udata);
}

void* LuaMalloc::malloc(size_t bytes)
{
	return m_alloc(m_udata,NULL,0,bytes);
}

void  LuaMalloc::free(void* mem)
{
	m_alloc(m_udata,mem,0,0);
}

void* LuaMalloc::realloc(void* mem, size_t newsize)
{
	return m_alloc(m_udata,mem,0,newsize); 
}


void LuaState::push(LuaObjectImpl* obj) {
	if (m_stack) {
		obj->m_prev = m_stack->m_prev;
		m_stack->m_prev->m_next = obj;
		m_stack->m_prev = obj;
		obj->m_next = NULL;
	}
	else {
		m_stack = obj;
		m_stack->m_prev = m_stack;
		m_stack->m_next = NULL;
	}
}

void LuaState::pop(LuaObjectImpl* obj) {
	
	if (obj->m_index >= 0) {
		assert(obj->m_index <= lua_gettop(getLuaState()));
		lua_remove(getLuaState(), obj->m_index);
		LuaObjectImpl* itr = obj->m_next;
		while (itr) {
			--(itr->m_index);//修改obj之后的索引
			itr = itr->m_next;
		}
	}

	if (obj == m_stack && obj->m_prev == obj) {
		m_stack = NULL;
	}
	else if (obj == m_stack) {
		obj->m_next->m_prev = obj->m_prev;
		m_stack = obj->m_next;
	}
	else {
		obj->m_prev->m_next = obj->m_next;
		if (obj->m_next) {
			obj->m_next->m_prev = obj->m_prev;
		}
		else {
			m_stack->m_prev = obj->m_prev;
		}
	}

	obj->m_prev = obj->m_next = NULL;
}


LuaState::LuaState(lua_State* L)
	:m_ls(L),m_stack()
{
}


LuaState::~LuaState(void)
{
}

LuaMalloc LuaState::getMalloc()
{
	return LuaMalloc(m_ls);
}

LuaObject LuaState::getGlobal(const char* name)
{
	return LuaObjectImpl::createGetGlobal(this,name);
}

LuaObject LuaState::getRegistery(const char* key)
{
	return LuaObjectImpl::createGetRegistery(this,key);
}

LuaObject LuaState::getRegistery(int key)
{
	return LuaObjectImpl::createGetRegistery(this,key);
}


LuaObject LuaState::getRegistery(void* key)
{
	return LuaObjectImpl::createGetRegistery(this,key);
}

void LuaState::setRegistry(const char* key,const LuaObject obj)
{
	lua_pushstring(m_ls,key);
	if (obj.isNone())
		lua_pushnil(m_ls);
	else
		lua_pushvalue(m_ls,obj.getIndex());
	lua_settable(m_ls, LUA_REGISTRYINDEX);
}

void LuaState::setRegistry(int key,const LuaObject obj)
{
	lua_pushinteger(m_ls,key);
	if (obj.isNone())
		lua_pushnil(m_ls);
	else
		lua_pushvalue(m_ls,obj.getIndex());
	lua_settable(m_ls, LUA_REGISTRYINDEX);
}

void LuaState::setRegistry(const void *key,const LuaObject obj)
{
	lua_pushlightuserdata(m_ls,const_cast<void*>(key));
	if (obj.isNone())
		lua_pushnil(m_ls);
	else
		lua_pushvalue(m_ls,obj.getIndex());
	lua_settable(m_ls, LUA_REGISTRYINDEX);
}



void LuaState::setGlobal(const char* name,LuaObject obj)
{
	if (obj.isNone())
		lua_pushnil(m_ls);
	else
		lua_pushvalue(m_ls,obj.getIndex());
	lua_setglobal(m_ls,name);
}

const char* getFieldName(const char* str,char* buf,int len)
{
	int i=0;
	while (*str)
	{
		if (*str=='.')
		{
			break;
		}
		else if(i<len)
			buf[i++]=*str;
		++str;
	}
	buf[i]='\0';
	if (*str=='.')
		++str;
	return str;
}


LuaObject LuaState::getField(const char* name)
{
	char buf[128];
	name=getFieldName(name,buf,sizeof(buf));
	LuaTable lg=getGlobal(buf);
	
	while (lg.isValid() && *name)
	{
		name=getFieldName(name,buf,sizeof(buf));
		lg=lg.getTable(buf);
	}

	if(*name=='\0')
		return lg;
	else
		return luaNil;
}


void LuaState::setField(const char* name, LuaObject obj)
{
	char buf[128];
	name = getFieldName(name, buf, sizeof(buf));
	LuaTable lg = getGlobal(buf);
	if (!lg.isValid())
	{
		lg = newTable();
		setGlobal(buf, lg);
	}

	while (lg.isValid() && *name)
	{
		name = getFieldName(name, buf, sizeof(buf));
		if (*name == '\0')
			break;
		LuaTable ltab = lg.getTable(buf);
		if (!ltab.isValid())
		{
			ltab = newTable();
			lg.setTable(buf, ltab);
		}
		lg = ltab;
	}

	lg.setTable(buf, obj);
}

LuaObject LuaState::newNil()
{
	return LuaObjectImpl::create(this);
}

LuaObject LuaState::newNumber(lua_Number num)
{
	return LuaObjectImpl::create(this,num);
}

LuaObject LuaState::newInt(lua_Integer num)
{
	return LuaObjectImpl::create(this,num);
}


LuaObject LuaState::newString(const char*str,int len)
{
	return LuaObjectImpl::create(this,str,len);
}

LuaObject LuaState::newString(const wchar_t* utf16,int len)
{
	if(len >= 0)
		StackOps::Push(m_ls, utf16, len);
	else
		StackOps::Push(m_ls, utf16);

	return LuaObjectImpl::createFromTop(this);
}

LuaObject LuaState::getObject(void * obj)
{
	LuaTable lobjects = getRegistery(&LuaOwnerState::s_object_key);
	return lobjects.getTable(obj);
}

void LuaState::setObject(void * ptr, LuaObject obj)
{
	LuaTable lobjects = getRegistery(&LuaOwnerState::s_object_key);
	lobjects.setTable(ptr, obj);
}

bool LuaState::setWeekTable(LuaTable ltab)
{
	if (!ltab.isTable())
	{
		return false;
	}

	//如果表已有meta表则直接设置mode
	LuaTable lmetatable = ltab.getMetatable();
	if (lmetatable.isTable()) {
		lmetatable.setTable("__mode", "v");
		return true;
	}


	//如果表没有meta表则设置meta表
	lmetatable = getRegistery("__week_table_value");
	if (!lmetatable.isTable())
	{
		lmetatable = newTable();
		lmetatable.setTable("__mode", "v");
		setRegistry("__week_table_value", lmetatable);
	}
	return ltab.setMetatable(lmetatable);
}

int LuaState::ref(LuaObject obj)
{
	int idx = obj.getIndex();
	if (idx)
		lua_pushvalue(m_ls, idx);
	else
		lua_pushnil(m_ls);

	return luaL_ref(m_ls,LUA_REGISTRYINDEX);
}

void LuaState::unref(int key)
{
	luaL_unref(m_ls,LUA_REGISTRYINDEX,key);
}

LuaObject LuaState::getRef(int key)
{
	lua_rawgeti(m_ls, LUA_REGISTRYINDEX,key);
	return LuaObjectImpl::createFromTop(this);
}

void LuaState::collectGarbage() {
	lua_gc(m_ls, LUA_GCCOLLECT, 0);
}

LuaOwnerState* LuaState::owner() {
	void* state = NULL;
	lua_getallocf(m_ls,&state);
	return (LuaOwnerState*)state;
}

LuaObject LuaState::newPtr(void* p)
{
	return LuaObjectImpl::create(this,p);
}

LuaObject LuaState::newData(void* p,size_t sz)
{
	return LuaObjectImpl::createData(this,p,sz);
}

LuaObject LuaState::newData(void** p, size_t sz) 
{
	*p = lua_newuserdata(m_ls, sz);
	return LuaObject(this, -1);
}

LuaObject LuaState::newData(size_t sz)
{
	return LuaObjectImpl::createData(this, sz);
}

LuaObject LuaState::newBool(bool b)
{
	return LuaObjectImpl::create(this,b);
}

LuaObject LuaState::newFunction(lua_CFunction f)
{
	lua_pushcfunction(m_ls, f);
	return LuaObjectImpl::createFromTop(this);
}

LuaObject LuaState::newFunction(LuaCFunction f)
{
	return LuaObjectImpl::create(this,f);
}


LuaTable LuaState::newTable(int arrSize, int hashSize)
{
	return LuaObjectImpl::createTable(this, arrSize,hashSize);
}

LuaThread LuaState::newThread()
{
    return LuaObjectImpl::createThread(this);
}

LuaTable LuaState::newLib(const LuaReg funcs[])
{
	LuaTable lib=LuaObjectImpl::createTable(this,0,0);

	for (int i=0;funcs[i].funcName &&funcs[i].func ;++i)
	{
		lib.setTable(funcs[i].funcName,newFunction(funcs[i].func));
	}
	return lib;
}

LuaObject LuaState::require(const char *file)
{
	LuaFunction require=getGlobal("require");
	if (require.isValid())
	{
		return require(file);
	}
	return newNil();
}


LuaObject LuaState::doFile(const char *fileName)
{
	if(luaL_loadfile(m_ls, fileName)!=LUA_OK || lua_pcall(m_ls, 0, 1, 0)!=LUA_OK)
	{
		std::string err=lua_tostring(m_ls,-1);
		lua_pop(m_ls,1);
		LUA_THROW_EXCEPTION(err.c_str());
		return luaNil;
	}
	else
	{
		return LuaObject(this,lua_gettop(m_ls));
	}
}


LuaObject LuaState::doString(const char *str)
{
	if(luaL_loadstring(m_ls, str)!=LUA_OK || lua_pcall(m_ls, 0, 1, 0)!=LUA_OK)
	{
		std::string err=lua_tostring(m_ls,-1);
		lua_pop(m_ls,1);
		LUA_THROW_EXCEPTION(err.c_str());
		return luaNil;
	}
	else
	{
		return LuaObject(this,lua_gettop(m_ls));
	}
}

LuaObject LuaState::doBuffer(const char *str, size_t len, const char* chunkName)
{
	if (luaL_loadbuffer(m_ls, str, len, chunkName) != LUA_OK || lua_pcall(m_ls, 0, 1, 0) != LUA_OK)
	{
		std::string err = lua_tostring(m_ls, -1);
		lua_pop(m_ls, 1);
		LUA_THROW_EXCEPTION(err.c_str());
		return luaNil;
	}
	else
	{
		return LuaObject(this, lua_gettop(m_ls));
	}
}


LuaObject LuaState::loadFile(const char *fileName)
{
	if(luaL_loadfile(m_ls, fileName)!=LUA_OK)
	{
		std::string err=lua_tostring(m_ls,-1);
		lua_pop(m_ls,1);
		LUA_THROW_EXCEPTION(err.c_str());
		return luaNil;
	}
	else
		return LuaObject(this,lua_gettop(m_ls));
}

LuaObject LuaState::loadString(const char *str)
{
	if(luaL_loadstring(m_ls, str)!=LUA_OK)
	{
		std::string err=lua_tostring(m_ls,-1);
		lua_pop(m_ls,1);
		LUA_THROW_EXCEPTION(err.c_str());
		return luaNil;
	}
	else
		return LuaObject(this,lua_gettop(m_ls));
}

LuaObject LuaState::loadBuffer(const char *str, size_t len, const char* chunkName)
{
	if (luaL_loadbuffer(m_ls, str, len, chunkName) != LUA_OK)
	{
		std::string err = lua_tostring(m_ls, -1);
		lua_pop(m_ls, 1);
		LUA_THROW_EXCEPTION(err.c_str());
		return luaNil;
	}
	else
		return LuaObject(this, lua_gettop(m_ls));
}

LuaObject  LuaState::loadFile(const char* fileName, LuaTable env) {
	LuaObject lfunc = loadFile(fileName);
	lfunc.setUpValue(1, env);
	return lfunc;
}

LuaObject LuaState::loadString(const char* str, LuaTable env) {
	LuaObject lfunc = loadString(str);
	lfunc.setUpValue(1, env);
	return lfunc;
}

LuaObject  LuaState::loadBuffer(const char* str, size_t len, const char* chunkName, LuaTable env) {
	LuaObject lfunc = loadBuffer(str, len,chunkName);
	lfunc.setUpValue(1, env);
	return lfunc;
}

int LuaState::error(const char* fmt,...)
{
	va_list argp;
	va_start(argp, fmt);
	luaL_where(m_ls, 1);
	lua_pushvfstring(m_ls, fmt, argp);
	va_end(argp);
	lua_concat(m_ls, 2);
	lua_error(m_ls);
	return 0;
}

void LuaState::addSearchPath(const char* path)
{
	lua_getglobal(m_ls, "package");                                  /* L: package */
	lua_getfield(m_ls, -1, "path");                /* get package.path, L: package path */
	const char* cur_path =  lua_tostring(m_ls, -1);
#ifdef WIN32
	lua_pushfstring(m_ls, "%s;%s\\?.lua", cur_path, path);            /* L: package path newpath */
#else
	lua_pushfstring(m_ls, "%s;%s/?.lua", cur_path, path);            /* L: package path newpath */
#endif
	lua_setfield(m_ls, -3, "path");          /* package.path = newpath, L: package path */
	lua_pop(m_ls, 2);                                                /* L: - */
}


#if LUA_VERSION_NUM > 501
#define SEARCHER_NAME "searchers"

#else
#define SEARCHER_NAME "loaders"
#endif


bool LuaState::addLuaLoader(lua_CFunction func)
{
	if (!func) return false;

	// stack content after the invoking of the function
	// get loader table
	lua_getglobal(m_ls, "package");                                  /* L: package */
	lua_getfield(m_ls, -1, SEARCHER_NAME);                           /* L: package, loaders */
	if (!lua_istable(m_ls, -1)) {
		lua_pop(m_ls, 1);
		return false;
	}

	// insert loader into index 2
	lua_pushcfunction(m_ls, func);                                   /* L: package, loaders, func */
	for (int i = (int)(lua_objlen(m_ls, -2) + 1); i > 2; --i)
	{
		lua_rawgeti(m_ls, -2, i - 1);                                /* L: package, loaders, func, function */
		// we call lua_rawgeti, so the loader table now is at -3
		lua_rawseti(m_ls, -3, i);                                    /* L: package, loaders, func */
	}
	lua_rawseti(m_ls, -2, 2);                                        /* L: package, loaders */

	// set loaders into package
	lua_setfield(m_ls, -2, SEARCHER_NAME);                            /* L: package */

	lua_pop(m_ls, 1);
	return true;
}

bool LuaState::addLuaLoader(LuaCFunction func)
{
	if (!func) return false;

	LuaObject lfunc = newFunction(func);
	// stack content after the invoking of the function
	// get loader table
	lua_getglobal(m_ls, "package");                                  /* L: package */
	lua_getfield(m_ls, -1, SEARCHER_NAME);                           /* L: package, loaders */

	if (!lua_istable(m_ls, -1)) {
		lua_pop(m_ls, 1);
		return false;
	}

																	 // insert loader into index 2
	lua_pushvalue(m_ls, lfunc.getIndex());							 /* L: package, loaders, func */
                              
	for (int i = (int)(lua_objlen(m_ls, -2) + 1); i > 2; --i)
	{
		lua_rawgeti(m_ls, -2, i - 1);                                /* L: package, loaders, func, function */
																	 // we call lua_rawgeti, so the loader table now is at -3
		lua_rawseti(m_ls, -3, i);                                    /* L: package, loaders, func */
	}
	lua_rawseti(m_ls, -2, 2);                                        /* L: package, loaders */

	// set loaders into package
	lua_setfield(m_ls, -2, SEARCHER_NAME);                           /* L: package */

	lua_pop(m_ls, 1);

	return true;
}

void LuaState::addLib(const luaL_Reg* lib)
{
	lua_getglobal(m_ls, "package");
	lua_getfield(m_ls, -1, "preload");
	for (; lib->func; lib++)
	{
		lua_pushcfunction(m_ls, lib->func);
		lua_setfield(m_ls, -2, lib->name);
	}
	lua_pop(m_ls, 2);
}

std::string LuaState::traceback()
{
	// 打印lua调用栈开始  
	int top = lua_gettop(m_ls);
	lua_getglobal(m_ls, "debug");
	lua_getfield(m_ls, -1, "traceback");
	int iError = lua_pcall(m_ls,    //VMachine    
		0,    //Argument Count    
		1,    //Return Value Count    
		0);
	size_t len = 0;
	const char* sz = lua_tolstring(m_ls, -1, &len);
	std::string s;
	if (len)
	{
		s.assign(sz, len);
	}
	lua_settop(m_ls,top);
	return s;
}

void LuaState::enumStack()
{
	lua_State *L=m_ls;
	int top = lua_gettop(L);

	printf("Stack:%d<************************\n",top);

	for(int i=1; i<=lua_gettop(L); ++i)
	{
		switch(lua_type(L, i))
		{
		case LUA_TNIL:
			printf("\t%s", lua_typename(L, lua_type(L, i)));
			break;
		case LUA_TBOOLEAN:
			printf("\t%s	%s", lua_typename(L, lua_type(L, i)), lua_toboolean(L, i)?"true":"false");
			break;
		case LUA_TLIGHTUSERDATA:
			printf("\t%s	0x%08p", lua_typename(L, lua_type(L, i)), lua_topointer(L, i));
			break;
		case LUA_TNUMBER:
			printf("\t%s	%.6f", lua_typename(L, lua_type(L, i)), lua_tonumber(L, i));
			break;
		case LUA_TSTRING:
			printf("\t%s	%s", lua_typename(L, lua_type(L, i)), lua_tostring(L, i));
			break;
		case LUA_TTABLE:
			printf("\t%s	0x%08p", lua_typename(L, lua_type(L, i)), lua_topointer(L, i));
			break;
		case LUA_TFUNCTION:
			printf("\t%s()	0x%08p", lua_typename(L, lua_type(L, i)), lua_topointer(L, i));
			break;
		case LUA_TUSERDATA:
			printf("\t%s	0x%08p", lua_typename(L, lua_type(L, i)), lua_topointer(L, i));
			break;
		case LUA_TTHREAD:
			printf("\t%s", lua_typename(L, lua_type(L, i)));
			break;
		}
	}

	printf("\n**************************>Stack\n");
}

////////////////////////////////////////////////////////////////////////////////////////


LuaFuncState::LuaFuncState(lua_State* L, bool skipSelf)
	:LuaState(L)
{
	if (skipSelf)
	{
		m_argCount = lua_gettop(L) - 1;
		if (m_argCount>LUA_MAX_ARG_COUNT)
			m_argCount = LUA_MAX_ARG_COUNT;

		for (int i = 0; i<m_argCount; ++i)
		{
			m_args[i] = LuaObjectImpl::createFromIndex(this, i+2);
		}
	}
	else
	{
		m_argCount = lua_gettop(L);
		if (m_argCount>LUA_MAX_ARG_COUNT)
			m_argCount = LUA_MAX_ARG_COUNT;

		for (int i = 0; i<m_argCount; ++i)
		{
			m_args[i] = LuaObjectImpl::createFromIndex(this, i + 1);
		}
	}
	

}

LuaObject LuaFuncState::arg(int idx) 
{
	if (idx >= m_argCount || idx < -m_argCount)
		return LuaObject();
	else if (idx >= 0)
		return m_args[idx];
	else
		return m_args[m_argCount + idx];
}

int LuaFuncState::argNum()
{
	return m_argCount;
}

int LuaFuncState::error(const char* fmt,...)
{
	va_list argp;
	va_start(argp, fmt);
	lua_pushvfstring(m_ls, fmt, argp);
	va_end(argp);
	lua_error(m_ls);
	return 0;
}




////////////////////////////////////////////////////////////////////////////////////////
int LuaOwnerState::s_object_key = 0;
int LuaOwnerState::s_loader_key = 0;

int LuaOwnerState::luaLoadScript(lua_State* L) {
	static const std::string BYTECODE_FILE_EXT = ".luac";
	static const std::string NOT_BYTECODE_FILE_EXT = ".lua";

	std::string filename(luaL_checkstring(L, 1));
	size_t pos = filename.rfind(NOT_BYTECODE_FILE_EXT);
	if (pos != std::string::npos){
		filename = filename.substr(0, pos);
	}

	pos = filename.find_first_of(".");
	while (pos != std::string::npos){
		filename.replace(pos, 1, "/");
		pos = filename.find_first_of(".");
	}

	lua_pushlightuserdata(L, &s_loader_key);
	lua_gettable(L, LUA_REGISTRYINDEX);
	LuaScriptLoader* loader = (LuaScriptLoader*)lua_topointer(L, -1);

	if (!loader) {
		return 0;
	}

	std::string searchpath;
	if (loader->searchPath()) {
		searchpath = loader->searchPath();
	}

	size_t begin = 0;
	size_t next = searchpath.find_first_of(";", 0);
	std::vector<char> buffer;
	std::string chunkName;

	do
	{
		if (next == std::string::npos) {
			next = searchpath.length();
		}else if (next == 0){
			begin = next + 1;
			next = searchpath.find_first_of(";", begin);
		}

		std::string prefix = searchpath.substr(begin, next);

		if (prefix[0] == '.' && prefix[1] == '/'){
			prefix = prefix.substr(2);
		}

		pos = prefix.find("?.lua");
		chunkName = prefix.substr(0, pos) + filename + BYTECODE_FILE_EXT;

		if (!loader->loadScript(chunkName, buffer)){
			chunkName = prefix.substr(0, pos) + filename + NOT_BYTECODE_FILE_EXT;
			loader->loadScript(chunkName, buffer);
		}

		begin = next + 1;
		next = searchpath.find_first_of(";", begin);
	} while (begin < (int)searchpath.length());

	filename.append(NOT_BYTECODE_FILE_EXT);

	if (!buffer.empty()){
		luaL_loadbuffer(L, buffer.data(), buffer.size(), filename.c_str());
		return 1;
	}else{
		return 0;
	}
}


int LuaOwnerState::luaRegisterObject(LuaFuncState& L)
{
	LuaTable ltab = L.arg(0);
	if (ltab.isValid())
	{
		typedef struct { void *pT; bool owner; } userdataType;
		LuaObject lptr = ltab.getTable("__ptr");
		assert(lptr.isUData());
		userdataType*data = (userdataType*)lptr.toData();
		if (data && data->pT)
		{
			LuaTable lobjects = L.getRegistery(&s_object_key);
			lobjects.setTable(data->pT, ltab);
			return L.rtn(true);
		}
	}
	return 0;
}


//扩展的setmetatable lua的只能设置表的metatable
int luaSetMetatable(lua_State* L)
{
	if((lua_istable(L,1) || lua_isuserdata(L,1))&& lua_istable(L,2))
	{
		lua_setmetatable(L,1);
		return 1;
	}
	else
	{
		luaL_error(L,"setmetatable param error");
		return 0;
	}
}

LuaOwnerState::LuaOwnerState()
	:LuaState(NULL),m_errorHandler(NULL), m_loader(NULL)
{
	m_ls=lua_newstate(luaAlloc,this);
    //m_ls=luaL_newstate();
	luaL_openlibs(m_ls);//初始化库

	lua_pushcfunction(m_ls,luaSetMetatable);
	lua_setglobal(m_ls,"__luaobj_setmetatable");

	//设置错误处理函数到registry
	lua_pushstring(m_ls, LUAOBJ_ERROR_HANDLER);
	lua_pushcfunction(m_ls, lerror_handler);
	lua_settable(m_ls, LUA_REGISTRYINDEX);
	lua_settop(m_ls,0);//清空栈

	//lua对象给C++调用
	LuaTable lobject = newTable();
	setWeekTable(lobject);//设置为弱表
	setRegistry(&s_object_key, lobject);

	setGlobal("__luaobj_registerObj", newFunction(luaRegisterObject));
}

LuaOwnerState::~LuaOwnerState()
{
	lua_close(m_ls);
}

void * LuaOwnerState::luaAlloc(void *ud, void *ptr, size_t, size_t nsize)
{
	LuaOwnerState *state=(LuaOwnerState*)ud;
	if (nsize == 0) {
		if(ptr)
			state->m_pool.free(ptr);
		return NULL;
	} else {  
		if(ptr)
			return state->m_pool.realloc(ptr,nsize);
		else
			return state->m_pool.malloc(nsize);
	}	
}


int LuaOwnerState::error(const char* fmt,...)
{
	char buf[1024]={0};
	va_list argp;
	va_start(argp, fmt);
	vsprintf(buf,fmt,argp);
	va_end(argp);

	if (m_errorHandler)
	{
		m_errorHandler(buf);
	}
	else
	{
		printf("%s",buf);
	}
	return 0;
}


int LuaOwnerState::lerror_handler(lua_State* L)
{
	lua_Debug debug = {};
	int ret = lua_getstack(L, 2, &debug); // 0是pcall_callback_err_fun自己, 1是error函数, 2是真正出错的函数
	lua_getinfo(L, "Sln", &debug);


	std::string err = lua_tostring(L,1);
	lua_pop(L, 1);
	std::stringstream msg;
	msg << debug.short_src << ":line " << debug.currentline;
	if (debug.name != 0) {
		msg << "(" << debug.namewhat << " " << debug.name << ")";
	}
	msg << " [" << err << "]";


	lua_getglobal(L, "debug");
	lua_getfield(L, -1, "traceback");
	int iError = lua_pcall(L,//VMachine    
		0,//Argument Count    
		1,//Return Value Count    
		0);

	const char* sz = lua_tostring(L, -1);
	if(sz)
		msg << sz;

	err = msg.str();
	lua_pushstring(L, err.c_str());
	printf("LUAERR:\n%s\n",err.c_str());
	return 1;
}

void LuaOwnerState::setScriptLoader(LuaScriptLoader* loader) {

	LuaObject lptr = getRegistery(&s_loader_key);
	if (lptr.isNil()) {
		addLuaLoader(luaLoadScript);
	}
	m_loader = loader;
	setRegistry(&s_loader_key, newPtr(m_loader));
}


///////////////////////////////////////////////////////////////

TlsValue LuaAutoState::s_tlsValue;

LuaAutoState::LuaAutoState()
{
	s_tlsValue.set(this);
}

LuaAutoState::~LuaAutoState()
{
	s_tlsValue.set(NULL);
}

LuaAutoState* LuaAutoState::current()
{
	return (LuaAutoState*)(s_tlsValue.get());
}

